package com.icongyou.enterprise.talent_analysis.service.impl;

import com.icongyou.enterprise.data_aggregation.service.DataAggregationService;
import com.icongyou.enterprise.talent_analysis.entity.DimensionDetail;
import com.icongyou.enterprise.talent_analysis.entity.MetricDetail;
import com.icongyou.enterprise.talent_analysis.entity.PortraitResponse;
import com.icongyou.enterprise.talent_analysis.service.PortraitService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@RequiredArgsConstructor
public class PortraitServiceImpl implements PortraitService {

    private final DataAggregationService dataAggregationService;

    private static final String DIM_TECH = "技术能力";
    private static final String DIM_PROB = "问题解决";
    private static final String DIM_LEARN = "学习能力";
    private static final String DIM_TEAM = "协作能力";
    private static final String DIM_COMM = "沟通能力";
    private static final String DIM_EXEC = "执行能力";

    @Override
    public PortraitResponse computeDefaultPortrait(String studentId) {
        Map<String, Object> raw = dataAggregationService.getStudentRawMetrics(studentId, 0.6d, 120, 7);

        PortraitResponse resp = new PortraitResponse();
        List<String> labels = Arrays.asList(DIM_TECH, DIM_PROB, DIM_LEARN, DIM_TEAM, DIM_COMM, DIM_EXEC);
        resp.getLabels().addAll(labels);

        // 构建每个维度的评分
        DimensionDetail tech = buildDimension(DIM_TECH, raw, new LinkedHashMap<String, Double>() {{
            put("avg_course_score", 0.6);
            put("avg_assignment_score", 0.4);
        }});

        DimensionDetail prob = buildDimension(DIM_PROB, raw, new LinkedHashMap<String, Double>() {{
            put("assignment_pass_rate", 0.6);
            put("submission_like_index", 0.4);
        }});

        DimensionDetail learn = buildDimension(DIM_LEARN, raw, new LinkedHashMap<String, Double>() {{
            put("course_completion_rate", 0.5);
            put("learning_speed_index", 0.3);
            put("rework_rate_inverse", 0.2);
        }});

        DimensionDetail team = buildDimension(DIM_TEAM, raw, new LinkedHashMap<String, Double>() {{
            put("contribution_rate_avg", 0.5);
            put("avg_team_score", 0.5);
        }});

        DimensionDetail comm = buildDimension(DIM_COMM, raw, new LinkedHashMap<String, Double>() {{
            put("teacher_comment_rate", 0.7);
            put("discussion_count", 0.3);
        }});

        DimensionDetail exec = buildDimension(DIM_EXEC, raw, new LinkedHashMap<String, Double>() {{
            put("on_time_submission_rate", 0.7);
            put("deadline_miss_inverse", 0.3);
        }});

        List<DimensionDetail> dims = Arrays.asList(tech, prob, learn, team, comm, exec);
        resp.setDimensions(dims);
        for (DimensionDetail d : dims) {
            resp.getScores().add(d.getScore());
        }
        return resp;
    }

    private DimensionDetail buildDimension(String name, Map<String, Object> raw, LinkedHashMap<String, Double> metricWeights) {
        DimensionDetail detail = new DimensionDetail();
        detail.setName(name);

        double weightedSum = 0.0;
        double appliedWeight = 0.0;
        boolean hasValidMetric = false;

        for (Map.Entry<String, Double> e : metricWeights.entrySet()) {
            String metric = e.getKey();
            double weight = e.getValue();
            Double rawVal = toDouble(raw.get(metric));
            Double normVal = normalize(metric, rawVal);

            if (normVal != null) {
                weightedSum += normVal * weight;
                appliedWeight += weight;
                hasValidMetric = true;
            }

            MetricDetail md = new MetricDetail(metric, rawVal, normVal, weight, sourceHint(metric), sqlHint(metric));
            detail.getDetails().add(md);
        }

        int score;
        if (!hasValidMetric || appliedWeight == 0) {
            detail.setScore(0.0);
            detail.setInsufficientData(true);
        } else {
            double hundredScale = clamp(weightedSum / appliedWeight, 0, 100);
            detail.setScore(roundToOneDecimal(hundredScale / 20.0)); // 映射到 0-5
            detail.setInsufficientData(false);
        }
        return detail;
    }

    private static Double toDouble(Object v) {
        if (v == null) return null;
        if (v instanceof Number) return ((Number) v).doubleValue();
        try {
            return Double.parseDouble(String.valueOf(v));
        } catch (Exception e) {
            return null;
        }
    }

    // 简化归一化：后续可替换为 cohort 百分位等
    private Double normalize(String metric, Double raw) {
        if (raw == null) return null;
        switch (metric) {
            case "avg_course_score":
            case "avg_assignment_score":
            case "avg_team_score":
            case "avg_course_total_score":
                // 0~100 直接
                return clamp(raw, 0, 100);
            case "assignment_pass_rate":
            case "course_completion_rate":
            case "rework_rate_inverse":
            case "on_time_submission_rate":
            case "deadline_miss_inverse":
            case "teacher_comment_rate":
                // 比率:若>1 视作百分数已换算
                return raw > 1 ? clamp(raw, 0, 100) : clamp(raw * 100, 0, 100);
            case "contribution_rate_avg":
                // 贡献度: 基于平均值(20%)的倍数关系评级
                // 0-20%(0-1倍): 0-60分 (低于平均)
                // 20-22%(1-1.1倍): 60-70分 (平均)
                // 22-30%(1.1-1.5倍): 70-85分 (良好)
                // 30%+(1.5倍以上): 85-100分 (优秀)
                // 效果: 20%→60分, 22%→70分, 30%→85分, 55%→100分
                double normalizedValue = raw <= 1 ? raw * 100 : raw; // 统一到0-100范围
                double contributionScore;
                if (normalizedValue <= 20) {
                    contributionScore = normalizedValue * 3.0; // 0-20 -> 0-60
                } else if (normalizedValue <= 22) {
                    contributionScore = 60 + (normalizedValue - 20) * 5.0; // 20-22 -> 60-70
                } else if (normalizedValue <= 30) {
                    contributionScore = 70 + (normalizedValue - 22) * 1.875; // 22-30 -> 70-85
                } else {
                    contributionScore = 85 + Math.min((normalizedValue - 30) * 0.6, 15); // 30+ -> 85-100
                }
                return clamp(contributionScore, 0, 100);
            case "learning_speed_index":
                // 期望/实际，设 cap=2.0（更快的上限）；
                double cap = 2.0;
                return clamp((raw > cap ? cap : raw) / cap * 100, 0, 100);
            case "submission_like_index":
                // 点赞+收藏均值，设 cap=10
                double likeCap = 10.0;
                return clamp((raw > likeCap ? likeCap : raw) / likeCap * 100, 0, 100);
            case "discussion_count":
                // 讨论次数，设 cap=10
                double discCap = 10.0;
                return clamp((raw > discCap ? discCap : raw) / discCap * 100, 0, 100);
            default:
                return null;
        }
    }

    private static double clamp(double v, double min, double max) {
        return Math.max(min, Math.min(max, v));
    }

    private double roundToOneDecimal(double value) {
        return Math.round(value * 10.0) / 10.0;
    }

    private String sourceHint(String metric) {
        switch (metric) {
            case "avg_course_score": return "course_students.score";
            case "avg_assignment_score": return "grades.final_score (via submissions)";
            case "assignment_pass_rate": return "grades.final_score & assignments.full_score";
            case "submission_like_index": return "submissions.like_count + submissions.favorite_count";
            case "course_completion_rate": return "course_progress.completed_tasks/pending_tasks";
            case "learning_speed_index": return "assignments.expected_duration & submissions.actual_duration";
            case "rework_rate_inverse": return "submissions count per assignment";
            case "contribution_rate_avg": return "submissions.contribution_rate (team)";
            case "avg_team_score": return "teams.current_score (join team_members)";
            case "teacher_comment_rate": return "grades.text_comment presence";
            case "discussion_count": return "discussion_records count";
            case "on_time_submission_rate": return "submissions.is_late";
            case "deadline_miss_inverse": return "assignments.end_time & submissions.submission_time";
            case "avg_course_total_score": return "course_progress.total_score";
            default: return "";
        }
    }

    private String sqlHint(String metric) {
        switch (metric) {
            case "avg_course_score": return "SELECT AVG(cs.score) FROM course_students cs WHERE cs.student_id = #{studentId}";
            case "avg_assignment_score": return "SELECT AVG(g.final_score) FROM grades g JOIN submissions s ON g.submission_id=s.submission_id WHERE s.student_id=#{studentId}";
            case "assignment_pass_rate": return "SELECT SUM(g.final_score >= a.full_score*#{passThreshold})/COUNT(*) FROM grades g JOIN submissions s ON g.submission_id=s.submission_id JOIN assignments a ON s.assignment_id=a.assignment_id WHERE s.student_id=#{studentId}";
            case "submission_like_index": return "SELECT AVG(s.like_count + s.favorite_count) FROM submissions s WHERE s.student_id=#{studentId}";
            case "course_completion_rate": return "SELECT SUM(cp.completed_tasks)/SUM(cp.completed_tasks+cp.pending_tasks) FROM course_progress cp WHERE cp.student_id=#{studentId}";
            case "learning_speed_index": return "SELECT AVG(a.expected_duration/NULLIF(s.actual_duration,0)) FROM submissions s JOIN assignments a ON s.assignment_id=a.assignment_id WHERE s.student_id=#{studentId}";
            case "rework_rate_inverse": return "derived: 1 - (multi_submit_assignments/total_assignments)";
            case "contribution_rate_avg": return "SELECT AVG(rate) FROM submissions s, JSON_TABLE(s.contribution_rate, '$[*]' COLUMNS(studentId VARCHAR(36) PATH '$.studentId', rate DECIMAL(5,2) PATH '$.rate')) AS jt WHERE jt.studentId=#{studentId} AND s.team_id IS NOT NULL";
            case "avg_team_score": return "SELECT AVG(t.current_score) FROM teams t JOIN team_members tm ON t.team_id=tm.team_id WHERE tm.student_id=#{studentId}";
            case "teacher_comment_rate": return "SELECT SUM(g.text_comment IS NOT NULL)/COUNT(*) FROM grades g JOIN submissions s ON g.submission_id=s.submission_id WHERE s.student_id=#{studentId}";
            case "discussion_count": return "SELECT COUNT(*) FROM discussion_records d WHERE d.student_id=#{studentId}";
            case "on_time_submission_rate": return "SELECT SUM(s.is_late=0)/COUNT(*) FROM submissions s WHERE s.student_id=#{studentId}";
            case "deadline_miss_inverse": return "SELECT 1-AVG(GREATEST(TIMESTAMPDIFF(DAY,a.end_time,s.submission_time),0))/#{maxLateDays} FROM submissions s JOIN assignments a ON s.assignment_id=a.assignment_id WHERE s.student_id=#{studentId}";
            case "avg_course_total_score": return "SELECT AVG(cp.total_score) FROM course_progress cp WHERE cp.student_id=#{studentId}";
            default: return "";
        }
    }
}
